/*
 * Copyright (c) 2016 Zibin Zheng <znbin@qq.com>
 * All rights reserved
 */

#ifndef _MULTI_BUTTON_H_
#define _MULTI_BUTTON_H_

#include <stdint.h>
#include <string.h>

// Configuration constants - can be modified according to your needs
#define TICKS_INTERVAL 5				   // ms - timer interrupt interval
#define DEBOUNCE_TICKS 3				   // MAX 7 (0 ~ 7) - debounce filter depth
#define SHORT_TICKS (300 / TICKS_INTERVAL) // short press threshold
#define LONG_TICKS (1000 / TICKS_INTERVAL) // long press threshold
#define PRESS_REPEAT_MAX_NUM 15			   // maximum repeat counter value

// Forward declaration
typedef struct _Button Button;

// Button callback function type
typedef void (*BtnCallback)(Button *btn_handle);

// Button event types
typedef enum
{
	BTN_PRESS_DOWN = 0,	  // button pressed down 按下事件
	BTN_PRESS_UP,		  // button released 抬起事件
	BTN_PRESS_REPEAT,	  // repeated press detected 重复按压
	BTN_SINGLE_CLICK,	  // single click completed 完成单击
	BTN_DOUBLE_CLICK,	  // double click completed 完整双击
	BTN_LONG_PRESS_START, // long press started 长按
	BTN_LONG_PRESS_HOLD,  // long press holding 长按保持
	BTN_EVENT_COUNT,	  // total number of events
	BTN_NONE_PRESS		  // no event
} ButtonEvent;

// Button state machine states
typedef enum
{
	BTN_STATE_IDLE = 0, // idle state
	BTN_STATE_PRESS,	// pressed state
	BTN_STATE_RELEASE,	// released state waiting for timeout
	BTN_STATE_REPEAT,	// repeat press state
	BTN_STATE_LONG_HOLD // long press hold state
} ButtonState;

// Button structure
struct _Button
{
	uint16_t ticks;									// tick counter
	uint8_t repeat : 4;								// repeat counter (0-15)
	uint8_t event : 4;								// current event (0-15)
	uint8_t state : 3;								// state machine state (0-7)
	uint8_t debounce_cnt : 3;						// debounce counter (0-7)
	uint8_t active_level : 1;						// active GPIO level (0 or 1)
	uint8_t button_level : 1;						// current button level
	uint8_t button_id;								// button identifier
	uint8_t (*hal_button_level)(uint8_t button_id); // HAL function to read GPIO
	BtnCallback cb[BTN_EVENT_COUNT];				// callback function array
	Button *next;									// next button in linked list
};

#ifdef __cplusplus
extern "C"
{
#endif

	// Public API functions
	void button_init(Button *handle, uint8_t (*pin_level)(uint8_t), uint8_t active_level, uint8_t button_id);
	void button_attach(Button *handle, ButtonEvent event, BtnCallback cb);
	void button_detach(Button *handle, ButtonEvent event);
	ButtonEvent button_get_event(Button *handle);
	int button_start(Button *handle);
	void button_stop(Button *handle);
	void button_ticks(void);

	// Utility functions
	uint8_t button_get_repeat_count(Button *handle);
	void button_reset(Button *handle);
	int button_is_pressed(Button *handle);

#ifdef __cplusplus
}
#endif

#endif
